home *** CD-ROM | disk | FTP | other *** search
/ PC Advisor 2010 April / PCA177.iso / ESSENTIALS / Firefox Setup.exe / nonlocalized / chrome / browser.jar / content / browser / pageinfo / pageInfo.js < prev    next >
Encoding:
JavaScript  |  2009-07-15  |  36.4 KB  |  1,129 lines

  1. //@line 42 "e:\builds\moz2_slave\win32_build\build\browser\base\content\pageinfo\pageInfo.js"
  2.  
  3. //******** define a js object to implement nsITreeView
  4. function pageInfoTreeView(columnids, copycol)
  5. {
  6.   // columnids is an array of strings indicating the names of the columns, in order
  7.   this.columnids = columnids;
  8.   this.colcount = columnids.length;
  9.  
  10.   // copycol is the index number for the column that we want to add to
  11.   // the copy-n-paste buffer when the user hits accel-c
  12.   this.copycol = copycol;
  13.   this.rows = 0;
  14.   this.tree = null;
  15.   this.data = [ ];
  16.   this.selection = null;
  17.   this.sortcol = null;
  18.   this.sortdir = 0;
  19. }
  20.  
  21. pageInfoTreeView.prototype = {
  22.   set rowCount(c) { throw "rowCount is a readonly property"; },
  23.   get rowCount() { return this.rows; },
  24.  
  25.   setTree: function(tree)
  26.   {
  27.     this.tree = tree;
  28.   },
  29.  
  30.   getCellText: function(row, column)
  31.   {
  32.     // row can be null, but js arrays are 0-indexed.
  33.     // colidx cannot be null, but can be larger than the number
  34.     // of columns in the array (when column is a string not in
  35.     // this.columnids.) In this case it's the fault of
  36.     // whoever typoed while calling this function.
  37.     return this.data[row][column.index] || "";
  38.   },
  39.  
  40.   setCellValue: function(row, column, value)
  41.   {
  42.   },
  43.  
  44.   setCellText: function(row, column, value)
  45.   {
  46.     this.data[row][column.index] = value;
  47.   },
  48.  
  49.   addRow: function(row)
  50.   {
  51.     this.rows = this.data.push(row);
  52.     this.rowCountChanged(this.rows - 1, 1);
  53.   },
  54.  
  55.   rowCountChanged: function(index, count)
  56.   {
  57.     this.tree.rowCountChanged(index, count);
  58.   },
  59.  
  60.   invalidate: function()
  61.   {
  62.     this.tree.invalidate();
  63.   },
  64.  
  65.   clear: function()
  66.   {
  67.     if (this.tree)
  68.       this.tree.rowCountChanged(0, -this.rows);
  69.     this.rows = 0;
  70.     this.data = [ ];
  71.   },
  72.  
  73.   handleCopy: function(row)
  74.   {
  75.     return (row < 0 || this.copycol < 0) ? "" : (this.data[row][this.copycol] || "");
  76.   },
  77.  
  78.   performActionOnRow: function(action, row)
  79.   {
  80.     if (action == "copy") {
  81.       var data = this.handleCopy(row)
  82.       this.tree.treeBody.parentNode.setAttribute("copybuffer", data);
  83.     }
  84.   },
  85.  
  86.   getRowProperties: function(row, prop) { },
  87.   getCellProperties: function(row, column, prop) { },
  88.   getColumnProperties: function(column, prop) { },
  89.   isContainer: function(index) { return false; },
  90.   isContainerOpen: function(index) { return false; },
  91.   isSeparator: function(index) { return false; },
  92.   isSorted: function() { },
  93.   canDrop: function(index, orientation) { return false; },
  94.   drop: function(row, orientation) { return false; },
  95.   getParentIndex: function(index) { return 0; },
  96.   hasNextSibling: function(index, after) { return false; },
  97.   getLevel: function(index) { return 0; },
  98.   getImageSrc: function(row, column) { },
  99.   getProgressMode: function(row, column) { },
  100.   getCellValue: function(row, column) { },
  101.   toggleOpenState: function(index) { },
  102.   cycleHeader: function(col) { },
  103.   selectionChanged: function() { },
  104.   cycleCell: function(row, column) { },
  105.   isEditable: function(row, column) { return false; },
  106.   isSelectable: function(row, column) { return false; },
  107.   performAction: function(action) { },
  108.   performActionOnCell: function(action, row, column) { }
  109. };
  110.  
  111. // mmm, yummy. global variables.
  112. var gWindow = null;
  113. var gDocument = null;
  114.  
  115. // column number to help using the data array
  116. const COL_IMAGE_ADDRESS = 0;
  117. const COL_IMAGE_TYPE    = 1;
  118. const COL_IMAGE_SIZE    = 2;
  119. const COL_IMAGE_ALT     = 3;
  120. const COL_IMAGE_COUNT   = 4;
  121. const COL_IMAGE_NODE    = 5;
  122. const COL_IMAGE_BG      = 6;
  123.  
  124. // column number to copy from, second argument to pageInfoTreeView's constructor
  125. const COPYCOL_NONE = -1;
  126. const COPYCOL_META_CONTENT = 1;
  127. const COPYCOL_IMAGE = COL_IMAGE_ADDRESS;
  128.  
  129. // one nsITreeView for each tree in the window
  130. var gMetaView = new pageInfoTreeView(["meta-name","meta-content"], COPYCOL_META_CONTENT);
  131. var gImageView = new pageInfoTreeView(["image-address","image-type","image-size",
  132.                                        "image-alt","image-count","image-node","image-bg"],
  133.                                       COPYCOL_IMAGE);
  134.  
  135. gImageView.getCellProperties = function(row, col, props) {
  136.   var aserv = Components.classes[ATOM_CONTRACTID]
  137.                         .getService(Components.interfaces.nsIAtomService);
  138.  
  139.   if (gImageView.data[row][COL_IMAGE_SIZE] == gStrings.unknown &&
  140.       !/^https:/.test(gImageView.data[row][COL_IMAGE_ADDRESS]))
  141.     props.AppendElement(aserv.getAtom("broken"));
  142. };
  143.  
  144. var gImageHash = { };
  145.  
  146. // localized strings (will be filled in when the document is loaded)
  147. // this isn't all of them, these are just the ones that would otherwise have been loaded inside a loop
  148. var gStrings = { };
  149. var gBundle;
  150.  
  151. const PERMISSION_CONTRACTID     = "@mozilla.org/permissionmanager;1";
  152. const PREFERENCES_CONTRACTID    = "@mozilla.org/preferences-service;1";
  153. const ATOM_CONTRACTID           = "@mozilla.org/atom-service;1";
  154.  
  155. // a number of services I'll need later
  156. // the cache services
  157. const nsICacheService = Components.interfaces.nsICacheService;
  158. const ACCESS_READ     = Components.interfaces.nsICache.ACCESS_READ;
  159. const cacheService = Components.classes["@mozilla.org/network/cache-service;1"].getService(nsICacheService);
  160. var httpCacheSession = cacheService.createSession("HTTP", 0, true);
  161. httpCacheSession.doomEntriesIfExpired = false;
  162. var ftpCacheSession = cacheService.createSession("FTP", 0, true);
  163. ftpCacheSession.doomEntriesIfExpired = false;
  164.  
  165. const nsICookiePermission  = Components.interfaces.nsICookiePermission;
  166. const nsIPermissionManager = Components.interfaces.nsIPermissionManager;
  167.  
  168. const nsICertificateDialogs = Components.interfaces.nsICertificateDialogs;
  169. const CERTIFICATEDIALOGS_CONTRACTID = "@mozilla.org/nsCertificateDialogs;1"
  170.  
  171. // clipboard helper
  172. try {
  173.   const gClipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);
  174. }
  175. catch(e) {
  176.   // do nothing, later code will handle the error
  177. }
  178.  
  179. // Interface for image loading content
  180. const nsIImageLoadingContent = Components.interfaces.nsIImageLoadingContent;
  181.  
  182. // namespaces, don't need all of these yet...
  183. const XLinkNS  = "http://www.w3.org/1999/xlink";
  184. const XULNS    = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  185. const XMLNS    = "http://www.w3.org/XML/1998/namespace";
  186. const XHTMLNS  = "http://www.w3.org/1999/xhtml";
  187. const XHTML2NS = "http://www.w3.org/2002/06/xhtml2"
  188.  
  189. const XHTMLNSre  = "^http\:\/\/www\.w3\.org\/1999\/xhtml$";
  190. const XHTML2NSre = "^http\:\/\/www\.w3\.org\/2002\/06\/xhtml2$";
  191. const XHTMLre = RegExp(XHTMLNSre + "|" + XHTML2NSre, "");
  192.  
  193. /* Overlays register functions here.
  194.  * These arrays are used to hold callbacks that Page Info will call at
  195.  * various stages. Use them by simply appending a function to them.
  196.  * For example, add a function to onLoadRegistry by invoking
  197.  *   "onLoadRegistry.push(XXXLoadFunc);"
  198.  * The XXXLoadFunc should be unique to the overlay module, and will be
  199.  * invoked as "XXXLoadFunc();"
  200.  */
  201.  
  202. // These functions are called to build the data displayed in the Page
  203. // Info window. The global variables gDocument and gWindow are set.
  204. var onLoadRegistry = [ ];
  205.  
  206. // These functions are called to remove old data still displayed in
  207. // the window when the document whose information is displayed
  208. // changes. For example, at this time, the list of images of the Media
  209. // tab is cleared.
  210. var onResetRegistry = [ ];
  211.  
  212. // These are called once for each subframe of the target document and
  213. // the target document itself. The frame is passed as an argument.
  214. var onProcessFrame = [ ];
  215.  
  216. // These functions are called once for each element (in all subframes, if any)
  217. // in the target document. The element is passed as an argument.
  218. var onProcessElement = [ ];
  219.  
  220. // These functions are called once when all the elements in all of the target
  221. // document (and all of its subframes, if any) have been processed
  222. var onFinished = [ ];
  223.  
  224. // These functions are called once when the Page Info window is closed.
  225. var onUnloadRegistry = [ ];
  226.  
  227.  
  228. /* Called when PageInfo window is loaded.  Arguments are:
  229.  *  window.arguments[0] - (optional) an object consisting of
  230.  *                         - doc: (optional) document to use for source. if not provided,
  231.  *                                the calling window's document will be used
  232.  *                         - initialTab: (optional) id of the inital tab to display
  233.  */
  234. function onLoadPageInfo()
  235. {
  236.   gBundle = document.getElementById("pageinfobundle");
  237.   gStrings.unknown = gBundle.getString("unknown");
  238.   gStrings.notSet = gBundle.getString("notset");
  239.   gStrings.mediaImg = gBundle.getString("mediaImg");
  240.   gStrings.mediaBGImg = gBundle.getString("mediaBGImg");
  241.   gStrings.mediaObject = gBundle.getString("mediaObject");
  242.   gStrings.mediaEmbed = gBundle.getString("mediaEmbed");
  243.   gStrings.mediaLink = gBundle.getString("mediaLink");
  244.   gStrings.mediaInput = gBundle.getString("mediaInput");
  245.  
  246.   if ("arguments" in window && window.arguments.length >= 1 &&
  247.        window.arguments[0] && window.arguments[0].doc) {
  248.     gDocument = window.arguments[0].doc;
  249.     gWindow = gDocument.defaultView;
  250.   }
  251.   else {
  252.     if ("gBrowser" in window.opener)
  253.       gWindow = window.opener.gBrowser.contentWindow;
  254.     else
  255.       gWindow = window.opener.frames[0];
  256.     gDocument = gWindow.document;
  257.   }
  258.  
  259.   // init media view
  260.   var imageTree = document.getElementById("imagetree");
  261.   imageTree.view = gImageView;
  262.  
  263.   // build the content
  264.   loadPageInfo();
  265.  
  266.   /* Select the requested tab, if the name is specified */
  267.   var initialTab = "generalTab";
  268.   if ("arguments" in window && window.arguments.length >= 1 &&
  269.        window.arguments[0] && window.arguments[0].initialTab)
  270.     initialTab = window.arguments[0].initialTab;
  271.   var radioGroup = document.getElementById("viewGroup");
  272.   initialTab = document.getElementById(initialTab) || document.getElementById("generalTab");
  273.   radioGroup.selectedItem = initialTab;
  274.   radioGroup.selectedItem.doCommand();
  275.   radioGroup.focus();
  276.   Components.classes["@mozilla.org/observer-service;1"]
  277.             .getService(Components.interfaces.nsIObserverService)
  278.             .notifyObservers(window, "page-info-dialog-loaded", null);
  279. }
  280.  
  281. function loadPageInfo()
  282. {
  283.   var titleFormat = gWindow != gWindow.top ? "pageInfo.frame.title"
  284.                                            : "pageInfo.page.title";
  285.   document.title = gBundle.getFormattedString(titleFormat, [gDocument.location]);
  286.  
  287.   document.getElementById("main-window").setAttribute("relatedUrl", gDocument.location);
  288.  
  289.   // do the easy stuff first
  290.   makeGeneralTab();
  291.  
  292.   // and then the hard stuff
  293.   makeTabs(gDocument, gWindow);
  294.  
  295.   initFeedTab();
  296.   onLoadPermission();
  297.  
  298.   /* Call registered overlay init functions */
  299.   onLoadRegistry.forEach(function(func) { func(); });
  300. }
  301.  
  302. function resetPageInfo()
  303. {
  304.   /* Reset Meta tags part */
  305.   gMetaView.clear();
  306.  
  307.   /* Reset Media tab */
  308.   var mediaTab = document.getElementById("mediaTab");
  309.   if (!mediaTab.hidden) {
  310.     Components.classes["@mozilla.org/observer-service;1"]
  311.               .getService(Components.interfaces.nsIObserverService)
  312.               .removeObserver(imagePermissionObserver, "perm-changed");
  313.     mediaTab.hidden = true;
  314.   }
  315.   gImageView.clear();
  316.   gImageHash = {};
  317.  
  318.   /* Reset Feeds Tab */
  319.   var feedListbox = document.getElementById("feedListbox");
  320.   while (feedListbox.firstChild)
  321.     feedListbox.removeChild(feedListbox.firstChild);
  322.  
  323.   /* Call registered overlay reset functions */
  324.   onResetRegistry.forEach(function(func) { func(); });
  325.  
  326.   /* And let's rebuild the data */
  327.   loadPageInfo();
  328. }
  329.  
  330. function onUnloadPageInfo()
  331. {
  332.   // Remove the observer, only if there is at least 1 image.
  333.   if (!document.getElementById("mediaTab").hidden) {
  334.     Components.classes["@mozilla.org/observer-service;1"]
  335.               .getService(Components.interfaces.nsIObserverService)
  336.               .removeObserver(imagePermissionObserver, "perm-changed");
  337.   }
  338.  
  339.   /* Call registered overlay unload functions */
  340.   onUnloadRegistry.forEach(function(func) { func(); });
  341. }
  342.  
  343. function doHelpButton()
  344. {
  345.   const helpTopics = {
  346.     "generalPanel":  "pageinfo_general",
  347.     "mediaPanel":    "pageinfo_media",
  348.     "feedPanel":     "pageinfo_feed",
  349.     "permPanel":     "pageinfo_permissions",
  350.     "securityPanel": "pageinfo_security"
  351.   };
  352.  
  353.   var deck  = document.getElementById("mainDeck");
  354.   var helpdoc = helpTopics[deck.selectedPanel.id] || "pageinfo_general";
  355.   openHelpLink(helpdoc);
  356. }
  357.  
  358. function showTab(id)
  359. {
  360.   var deck  = document.getElementById("mainDeck");
  361.   var pagel = document.getElementById(id + "Panel");
  362.   deck.selectedPanel = pagel;
  363. }
  364.  
  365. function onClickMore()
  366. {
  367.   var radioGrp = document.getElementById("viewGroup");
  368.   var radioElt = document.getElementById("securityTab");
  369.   radioGrp.selectedItem = radioElt;
  370.   showTab('security');
  371. }
  372.  
  373. function toggleGroupbox(id)
  374. {
  375.   var elt = document.getElementById(id);
  376.   if (elt.hasAttribute("closed")) {
  377.     elt.removeAttribute("closed");
  378.     if (elt.flexWhenOpened)
  379.       elt.flex = elt.flexWhenOpened;
  380.   }
  381.   else {
  382.     elt.setAttribute("closed", "true");
  383.     if (elt.flex) {
  384.       elt.flexWhenOpened = elt.flex;
  385.       elt.flex = 0;
  386.     }
  387.   }
  388. }
  389.  
  390. function makeGeneralTab()
  391. {
  392.   var title = (gDocument.title) ? gBundle.getFormattedString("pageTitle", [gDocument.title]) : gBundle.getString("noPageTitle");
  393.   document.getElementById("titletext").value = title;
  394.  
  395.   var url = gDocument.location.toString();
  396.   setItemValue("urltext", url);
  397.  
  398.   var referrer = ("referrer" in gDocument && gDocument.referrer);
  399.   setItemValue("refertext", referrer);
  400.  
  401.   var mode = ("compatMode" in gDocument && gDocument.compatMode == "BackCompat") ? "generalQuirksMode" : "generalStrictMode";
  402.   document.getElementById("modetext").value = gBundle.getString(mode);
  403.  
  404.   // find out the mime type
  405.   var mimeType = gDocument.contentType;
  406.   setItemValue("typetext", mimeType);
  407.  
  408.   // get the document characterset
  409.   var encoding = gDocument.characterSet;
  410.   document.getElementById("encodingtext").value = encoding;
  411.  
  412.   // get the meta tags
  413.   var metaNodes = gDocument.getElementsByTagName("meta");
  414.   var length = metaNodes.length;
  415.  
  416.   var metaGroup = document.getElementById("metaTags");
  417.   if (!length)
  418.     metaGroup.collapsed = true;
  419.   else {
  420.     var metaTagsCaption = document.getElementById("metaTagsCaption");
  421.     if (length == 1)
  422.       metaTagsCaption.label = gBundle.getString("generalMetaTag");
  423.     else
  424.       metaTagsCaption.label = gBundle.getFormattedString("generalMetaTags", [length]);
  425.     var metaTree = document.getElementById("metatree");
  426.     metaTree.treeBoxObject.view = gMetaView;
  427.  
  428.     for (var i = 0; i < length; i++)
  429.       gMetaView.addRow([metaNodes[i].name || metaNodes[i].httpEquiv, metaNodes[i].content]);
  430.  
  431.     metaGroup.collapsed = false;
  432.   }
  433.  
  434.   // get the date of last modification
  435.   var modifiedText = formatDate(gDocument.lastModified, gStrings.notSet);
  436.   document.getElementById("modifiedtext").value = modifiedText;
  437.  
  438.   // get cache info
  439.   var cacheKey = url.replace(/#.*$/, "");
  440.   try {
  441.     var cacheEntryDescriptor = httpCacheSession.openCacheEntry(cacheKey, ACCESS_READ, false);
  442.   }
  443.   catch(ex) {
  444.     try {
  445.       cacheEntryDescriptor = ftpCacheSession.openCacheEntry(cacheKey, ACCESS_READ, false);
  446.     }
  447.     catch(ex2) { }
  448.   }
  449.  
  450.   var sizeText;
  451.   if (cacheEntryDescriptor) {
  452.     var pageSize = cacheEntryDescriptor.dataSize;
  453.     var kbSize = formatNumber(Math.round(pageSize / 1024 * 100) / 100);
  454.     sizeText = gBundle.getFormattedString("generalSize", [kbSize, formatNumber(pageSize)]);
  455.   }
  456.   setItemValue("sizetext", sizeText);
  457.  
  458.   securityOnLoad();
  459. }
  460.  
  461. //******** Generic Build-a-tab
  462. // Assumes the views are empty. Only called once to build the tabs, and
  463. // does so by farming the task off to another thread via setTimeout().
  464. // The actual work is done with a TreeWalker that calls doGrab() once for
  465. // each element node in the document.
  466.  
  467. var gFrameList = [ ];
  468.  
  469. function makeTabs(aDocument, aWindow)
  470. {
  471.   goThroughFrames(aDocument, aWindow);
  472.   processFrames();
  473. }
  474.  
  475. function goThroughFrames(aDocument, aWindow)
  476. {
  477.   gFrameList.push(aDocument);
  478.   if (aWindow && aWindow.frames.length > 0) {
  479.     var num = aWindow.frames.length;
  480.     for (var i = 0; i < num; i++)
  481.       goThroughFrames(aWindow.frames[i].document, aWindow.frames[i]);  // recurse through the frames
  482.   }
  483. }
  484.  
  485. function processFrames()
  486. {
  487.   if (gFrameList.length) {
  488.     var doc = gFrameList[0];
  489.     onProcessFrame.forEach(function(func) { func(doc); });
  490.     var iterator = doc.createTreeWalker(doc, NodeFilter.SHOW_ELEMENT, grabAll, true);
  491.     gFrameList.shift();
  492.     setTimeout(doGrab, 16, iterator);
  493.   }
  494.   else
  495.     onFinished.forEach(function(func) { func(); });
  496. }
  497.  
  498. function doGrab(iterator)
  499. {
  500.   for (var i = 0; i < 50; ++i)
  501.     if (!iterator.nextNode()) {
  502.       processFrames();
  503.       return;
  504.     }
  505.  
  506.   setTimeout(doGrab, 16, iterator);
  507. }
  508.  
  509. function ensureSelection(view)
  510. {
  511.   // only select something if nothing is currently selected
  512.   // and if there's anything to select
  513.   if (view.selection.count == 0 && view.rowCount)
  514.     view.selection.select(0);
  515. }
  516.  
  517. function addImage(url, type, alt, elem, isBg)
  518. {
  519.   if (!url)
  520.     return;
  521.  
  522.   if (!gImageHash.hasOwnProperty(url))
  523.     gImageHash[url] = { };
  524.   if (!gImageHash[url].hasOwnProperty(type))
  525.     gImageHash[url][type] = { };
  526.   if (!gImageHash[url][type].hasOwnProperty(alt)) {
  527.     gImageHash[url][type][alt] = gImageView.data.length;
  528.     try {
  529.       // open for READ, in non-blocking mode
  530.       var cacheEntryDescriptor = httpCacheSession.openCacheEntry(url, ACCESS_READ, false);
  531.     }
  532.     catch(ex) {
  533.       try {
  534.         // open for READ, in non-blocking mode
  535.         cacheEntryDescriptor = ftpCacheSession.openCacheEntry(url, ACCESS_READ, false);
  536.       }
  537.       catch(ex2) { }
  538.     }
  539.  
  540.     var sizeText;
  541.     if (cacheEntryDescriptor) {
  542.       var pageSize = cacheEntryDescriptor.dataSize;
  543.       var kbSize = formatNumber(Math.round(pageSize / 1024 * 100) / 100);
  544.       sizeText = gBundle.getFormattedString("mediaFileSize", [kbSize]);
  545.     }
  546.     else
  547.       sizeText = gStrings.unknown;
  548.     gImageView.addRow([url, type, sizeText, alt, 1, elem, isBg]);
  549.  
  550.     // Add the observer, only once.
  551.     if (gImageView.data.length == 1) {
  552.       document.getElementById("mediaTab").hidden = false;
  553.       Components.classes["@mozilla.org/observer-service;1"]
  554.                 .getService(Components.interfaces.nsIObserverService)
  555.                 .addObserver(imagePermissionObserver, "perm-changed", false);
  556.     }
  557.   }
  558.   else {
  559.     var i = gImageHash[url][type][alt];
  560.     gImageView.data[i][COL_IMAGE_COUNT]++;
  561.   }
  562. }
  563.  
  564. function grabAll(elem)
  565. {
  566.   // check for background images, any node may have one
  567.   var ComputedStyle = elem.ownerDocument.defaultView.getComputedStyle(elem, "");
  568.   var url = ComputedStyle && ComputedStyle.getPropertyCSSValue("background-image");
  569.   if (url && url.primitiveType == CSSPrimitiveValue.CSS_URI)
  570.     addImage(url.getStringValue(), gStrings.mediaBGImg, gStrings.notSet, elem, true);
  571.  
  572.   // one swi^H^H^Hif-else to rule them all
  573.   if (elem instanceof HTMLImageElement)
  574.     addImage(elem.src, gStrings.mediaImg,
  575.              (elem.hasAttribute("alt")) ? elem.alt : gStrings.notSet, elem, false);
  576. //@line 617 "e:\builds\moz2_slave\win32_build\build\browser\base\content\pageinfo\pageInfo.js"
  577.   else if (elem instanceof SVGImageElement) {
  578.     try {
  579.       // Note: makeURLAbsolute will throw if either the baseURI is not a valid URI
  580.       //       or the URI formed from the baseURI and the URL is not a valid URI
  581.       var href = makeURLAbsolute(elem.baseURI, elem.href.baseVal);
  582.       addImage(href, gStrings.mediaImg, "", elem, false);
  583.     } catch (e) { }
  584.   }
  585. //@line 626 "e:\builds\moz2_slave\win32_build\build\browser\base\content\pageinfo\pageInfo.js"
  586.   else if (elem instanceof HTMLLinkElement) {
  587.     if (elem.rel && /\bicon\b/i.test(elem.rel))
  588.       addImage(elem.href, gStrings.mediaLink, "", elem, false);
  589.   }
  590.   else if (elem instanceof HTMLInputElement || elem instanceof HTMLButtonElement) {
  591.     if (elem.type.toLowerCase() == "image")
  592.       addImage(elem.src, gStrings.mediaInput,
  593.                (elem.hasAttribute("alt")) ? elem.alt : gStrings.notSet, elem, false);
  594.   }
  595.   else if (elem instanceof HTMLObjectElement)
  596.     addImage(elem.data, gStrings.mediaObject, getValueText(elem), elem, false);
  597.   else if (elem instanceof HTMLEmbedElement)
  598.     addImage(elem.src, gStrings.mediaEmbed, "", elem, false);
  599.  
  600.   onProcessElement.forEach(function(func) { func(elem); });
  601.  
  602.   return NodeFilter.FILTER_ACCEPT;
  603. }
  604.  
  605. //******** Link Stuff
  606. function openURL(target)
  607. {
  608.   var url = target.parentNode.childNodes[2].value;
  609.   window.open(url, "_blank", "chrome");
  610. }
  611.  
  612. function onBeginLinkDrag(event,urlField,descField)
  613. {
  614.   if (event.originalTarget.localName != "treechildren")
  615.     return;
  616.  
  617.   var tree = event.target;
  618.   if (!("treeBoxObject" in tree))
  619.     tree = tree.parentNode;
  620.  
  621.   var row = tree.treeBoxObject.getRowAt(event.clientX, event.clientY);
  622.   if (row == -1)
  623.     return;
  624.  
  625.   // Adding URL flavor
  626.   var col = tree.columns[urlField];
  627.   var url = tree.view.getCellText(row, col);
  628.   col = tree.columns[descField];
  629.   var desc = tree.view.getCellText(row, col);
  630.  
  631.   var dt = event.dataTransfer;
  632.   dt.setData("text/x-moz-url", url + "\n" + desc);
  633.   dt.setData("text/url-list", url);
  634.   dt.setData("text/plain", url);
  635. }
  636.  
  637. //******** Image Stuff
  638. function getSelectedImage(tree)
  639. {
  640.   if (!gImageView.rowCount)
  641.     return null;
  642.  
  643.   // Only works if only one item is selected
  644.   var clickedRow = tree.currentIndex;
  645.   // image-node
  646.   return gImageView.data[clickedRow][COL_IMAGE_NODE];
  647. }
  648.  
  649. function selectSaveFolder()
  650. {
  651.   const nsILocalFile = Components.interfaces.nsILocalFile;
  652.   const nsIFilePicker = Components.interfaces.nsIFilePicker;
  653.   var fp = Components.classes["@mozilla.org/filepicker;1"]
  654.                      .createInstance(nsIFilePicker);
  655.  
  656.   var titleText = gBundle.getString("mediaSelectFolder");
  657.   fp.init(window, titleText, nsIFilePicker.modeGetFolder);
  658.   try {
  659.     var prefs = Components.classes[PREFERENCES_CONTRACTID]
  660.                           .getService(Components.interfaces.nsIPrefBranch2);
  661.  
  662.     var initialDir = prefs.getComplexValue("browser.download.dir", nsILocalFile);
  663.     if (initialDir)
  664.       fp.displayDirectory = initialDir;
  665.   }
  666.   catch (ex) { }
  667.  
  668.   fp.appendFilters(nsIFilePicker.filterAll);
  669.   var ret = fp.show();
  670.  
  671.   if (ret == nsIFilePicker.returnOK)
  672.     return fp.file.QueryInterface(nsILocalFile);
  673.   return null;
  674. }
  675.  
  676. function saveMedia()
  677. {
  678.   var tree = document.getElementById("imagetree");
  679.   var count = tree.view.selection.count;
  680.   if (count == 1) {
  681.     var item = getSelectedImage(tree);
  682.     var url = gImageView.data[tree.currentIndex][COL_IMAGE_ADDRESS];
  683.  
  684.     if (url)
  685.       saveURL(url, null, "SaveImageTitle", false, false, makeURI(item.baseURI));
  686.   }
  687.   else {
  688.     var odir  = selectSaveFolder();
  689.     var start = { };
  690.     var end   = { };
  691.     var numRanges = tree.view.selection.getRangeCount();
  692.  
  693.     var rowArray = [ ];
  694.     for (var t = 0; t < numRanges; t++) {
  695.       tree.view.selection.getRangeAt(t, start, end);
  696.       for (var v = start.value; v <= end.value; v++)
  697.         rowArray.push(v);
  698.     }
  699.  
  700.     var saveAnImage = function(aURIString, aChosenData, aBaseURI) {
  701.       internalSave(aURIString, null, null, null, null, false, "SaveImageTitle",
  702.                    aChosenData, aBaseURI);
  703.     }
  704.  
  705.     for (var i = 0; i < rowArray.length; i++) {
  706.       var v = rowArray[i];
  707.       var dir = odir.clone();
  708.       var item = gImageView.data[v][COL_IMAGE_NODE];
  709.       var uriString = gImageView.data[v][COL_IMAGE_ADDRESS];
  710.       var uri = makeURI(uriString);
  711.  
  712.       try {
  713.         uri.QueryInterface(Components.interfaces.nsIURL);
  714.         dir.append(decodeURIComponent(uri.fileName));
  715.       }
  716.       catch(ex) { /* data: uris */ }
  717.  
  718.       if (i == 0)
  719.         saveAnImage(uriString, new AutoChosen(dir, uri), makeURI(item.baseURI));
  720.       else {
  721.         // This delay is a hack which prevents the download manager
  722.         // from opening many times. See bug 377339.
  723.         setTimeout(saveAnImage, 200, uriString, new AutoChosen(dir, uri),
  724.                    makeURI(item.baseURI));
  725.       }
  726.     }
  727.   }
  728. }
  729.  
  730. function onBlockImage()
  731. {
  732.   var permissionManager = Components.classes[PERMISSION_CONTRACTID]
  733.                                     .getService(nsIPermissionManager);
  734.  
  735.   var checkbox = document.getElementById("blockImage");
  736.   var uri = makeURI(document.getElementById("imageurltext").value);
  737.   if (checkbox.checked)
  738.     permissionManager.add(uri, "image", nsIPermissionManager.DENY_ACTION);
  739.   else
  740.     permissionManager.remove(uri.host, "image");
  741. }
  742.  
  743. function onImageSelect()
  744. {
  745.   var previewBox   = document.getElementById("mediaPreviewBox");
  746.   var mediaSaveBox = document.getElementById("mediaSaveBox");
  747.   var splitter     = document.getElementById("mediaSplitter");
  748.   var tree = document.getElementById("imagetree");
  749.   var count = tree.view.selection.count;
  750.   if (count == 0) {
  751.     previewBox.collapsed   = true;
  752.     mediaSaveBox.collapsed = true;
  753.     splitter.collapsed     = true;
  754.     tree.flex = 1;
  755.   }
  756.   else if (count > 1) {
  757.     splitter.collapsed     = true;
  758.     previewBox.collapsed   = true;
  759.     mediaSaveBox.collapsed = false;
  760.     tree.flex = 1;
  761.   }
  762.   else {
  763.     mediaSaveBox.collapsed = true;
  764.     splitter.collapsed     = false;
  765.     previewBox.collapsed   = false;
  766.     tree.flex = 0;
  767.     makePreview(tree.view.selection.currentIndex);
  768.   }
  769. }
  770.  
  771. function makePreview(row)
  772. {
  773.   var imageTree = document.getElementById("imagetree");
  774.   var item = getSelectedImage(imageTree);
  775.   var url = gImageView.data[row][COL_IMAGE_ADDRESS];
  776.   var isBG = gImageView.data[row][COL_IMAGE_BG];
  777.  
  778.   setItemValue("imageurltext", url);
  779.  
  780.   var imageText;
  781.   if (!isBG &&
  782. //@line 823 "e:\builds\moz2_slave\win32_build\build\browser\base\content\pageinfo\pageInfo.js"
  783.       !(item instanceof SVGImageElement) &&
  784. //@line 825 "e:\builds\moz2_slave\win32_build\build\browser\base\content\pageinfo\pageInfo.js"
  785.       !(gDocument instanceof ImageDocument)) {
  786.     imageText = item.title || item.alt;
  787.  
  788.     if (!imageText && !(item instanceof HTMLImageElement))
  789.       imageText = getValueText(item);
  790.   }
  791.   setItemValue("imagetext", imageText);
  792.  
  793.   setItemValue("imagelongdesctext", item.longDesc);
  794.  
  795.   // get cache info
  796.   var cacheKey = url.replace(/#.*$/, "");
  797.   try {
  798.     // open for READ, in non-blocking mode
  799.     var cacheEntryDescriptor = httpCacheSession.openCacheEntry(cacheKey, ACCESS_READ, false);
  800.   }
  801.   catch(ex) {
  802.     try {
  803.       // open for READ, in non-blocking mode
  804.       cacheEntryDescriptor = ftpCacheSession.openCacheEntry(cacheKey, ACCESS_READ, false);
  805.     }
  806.     catch(ex2) { }
  807.   }
  808.  
  809.   // find out the file size
  810.   var sizeText;
  811.   if (cacheEntryDescriptor) {
  812.     var imageSize = cacheEntryDescriptor.dataSize;
  813.     var kbSize = Math.round(imageSize / 1024 * 100) / 100;
  814.     sizeText = gBundle.getFormattedString("generalSize",
  815.                                           [formatNumber(kbSize), formatNumber(imageSize)]);
  816.   }
  817.   else
  818.     sizeText = gBundle.getString("mediaUnknownNotCached");
  819.   setItemValue("imagesizetext", sizeText);
  820.  
  821.   var mimeType;
  822.   var numFrames = 1;
  823.   if (item instanceof HTMLObjectElement ||
  824.       item instanceof HTMLEmbedElement ||
  825.       item instanceof HTMLLinkElement)
  826.     mimeType = item.type;
  827.  
  828.   if (!mimeType && !isBG && item instanceof nsIImageLoadingContent) {
  829.     var imageRequest = item.getRequest(nsIImageLoadingContent.CURRENT_REQUEST);
  830.     if (imageRequest) {
  831.       mimeType = imageRequest.mimeType;
  832.       var image = imageRequest.image;
  833.       if (image)
  834.         numFrames = image.numFrames;
  835.     }
  836.   }
  837.   if (!mimeType)
  838.     mimeType = getContentTypeFromHeaders(cacheEntryDescriptor);
  839.  
  840.   var imageType;
  841.   if (mimeType) {
  842.     // We found the type, try to display it nicely
  843.     var imageMimeType = /^image\/(.*)/.exec(mimeType);
  844.     if (imageMimeType) {
  845.       imageType = imageMimeType[1].toUpperCase();
  846.       if (numFrames > 1)
  847.         imageType = gBundle.getFormattedString("mediaAnimatedImageType",
  848.                                                [imageType, numFrames]);
  849.       else
  850.         imageType = gBundle.getFormattedString("mediaImageType", [imageType]);
  851.     }
  852.     else {
  853.       // the MIME type doesn't begin with image/, display the raw type
  854.       imageType = mimeType;
  855.     }
  856.   }
  857.   else {
  858.     // We couldn't find the type, fall back to the value in the treeview
  859.     imageType = gImageView.data[row][COL_IMAGE_TYPE];
  860.   }
  861.   setItemValue("imagetypetext", imageType);
  862.  
  863.   var imageContainer = document.getElementById("theimagecontainer");
  864.   var oldImage = document.getElementById("thepreviewimage");
  865.  
  866.   const regex = /^(https?|ftp|file|gopher|about|chrome|resource):/;
  867.   var isProtocolAllowed = regex.test(url);
  868.   if (/^data:/.test(url) && /^image\//.test(mimeType))
  869.     isProtocolAllowed = true;
  870.  
  871.   var newImage = new Image();
  872.   newImage.setAttribute("id", "thepreviewimage");
  873.   var physWidth = 0, physHeight = 0;
  874.   var width = 0, height = 0;
  875.  
  876.   if ((item instanceof HTMLLinkElement || item instanceof HTMLInputElement ||
  877.        item instanceof HTMLImageElement ||
  878. //@line 919 "e:\builds\moz2_slave\win32_build\build\browser\base\content\pageinfo\pageInfo.js"
  879.        item instanceof SVGImageElement ||
  880. //@line 921 "e:\builds\moz2_slave\win32_build\build\browser\base\content\pageinfo\pageInfo.js"
  881.       (item instanceof HTMLObjectElement && /^image\//.test(mimeType)) || isBG) && isProtocolAllowed) {
  882.     newImage.setAttribute("src", url);
  883.     physWidth = newImage.width || 0;
  884.     physHeight = newImage.height || 0;
  885.  
  886.     // "width" and "height" attributes must be set to newImage,
  887.     // even if there is no "width" or "height attribute in item;
  888.     // otherwise, the preview image cannot be displayed correctly.
  889.     if (!isBG) {
  890.       newImage.width = ("width" in item && item.width) || newImage.naturalWidth;
  891.       newImage.height = ("height" in item && item.height) || newImage.naturalHeight;
  892.     }
  893.     else {
  894.       // the Width and Height of an HTML tag should not be used for its background image
  895.       // (for example, "table" can have "width" or "height" attributes)
  896.       newImage.width = newImage.naturalWidth;
  897.       newImage.height = newImage.naturalHeight;
  898.     }
  899.  
  900. //@line 941 "e:\builds\moz2_slave\win32_build\build\browser\base\content\pageinfo\pageInfo.js"
  901.     if (item instanceof SVGImageElement) {
  902.       newImage.width = item.width.baseVal.value;
  903.       newImage.height = item.height.baseVal.value;
  904.     }
  905. //@line 946 "e:\builds\moz2_slave\win32_build\build\browser\base\content\pageinfo\pageInfo.js"
  906.  
  907.     width = newImage.width;
  908.     height = newImage.height;
  909.  
  910.     document.getElementById("theimagecontainer").collapsed = false
  911.     document.getElementById("brokenimagecontainer").collapsed = true;
  912.   }
  913.   else {
  914.     // fallback image for protocols not allowed (e.g., data: or javascript:)
  915.     // or elements not [yet] handled (e.g., object, embed).
  916.     document.getElementById("brokenimagecontainer").collapsed = false;
  917.     document.getElementById("theimagecontainer").collapsed = true;
  918.   }
  919.  
  920.   var imageSize = "";
  921.   if (url) {
  922.     if (width != physWidth || height != physHeight) {
  923.       imageSize = gBundle.getFormattedString("mediaDimensionsScaled",
  924.                                              [formatNumber(physWidth),
  925.                                               formatNumber(physHeight),
  926.                                               formatNumber(width),
  927.                                               formatNumber(height)]);
  928.     }
  929.     else {
  930.       imageSize = gBundle.getFormattedString("mediaDimensions",
  931.                                              [formatNumber(width),
  932.                                               formatNumber(height)]);
  933.     }
  934.   }
  935.   setItemValue("imagedimensiontext", imageSize);
  936.  
  937.   makeBlockImage(url);
  938.  
  939.   imageContainer.removeChild(oldImage);
  940.   imageContainer.appendChild(newImage);
  941. }
  942.  
  943. function makeBlockImage(url)
  944. {
  945.   var permissionManager = Components.classes[PERMISSION_CONTRACTID]
  946.                                     .getService(nsIPermissionManager);
  947.   var prefs = Components.classes[PREFERENCES_CONTRACTID]
  948.                         .getService(Components.interfaces.nsIPrefBranch2);
  949.  
  950.   var checkbox = document.getElementById("blockImage");
  951.   var imagePref = prefs.getIntPref("permissions.default.image");
  952.   if (!(/^https?:/.test(url)) || imagePref == 2)
  953.     // We can't block the images from this host because either is is not
  954.     // for http(s) or we don't load images at all
  955.     checkbox.hidden = true;
  956.   else {
  957.     var uri = makeURI(url);
  958.     if (uri.host) {
  959.       checkbox.hidden = false;
  960.       checkbox.label = gBundle.getFormattedString("mediaBlockImage", [uri.host]);
  961.       var perm = permissionManager.testPermission(uri, "image");
  962.       checkbox.checked = perm == nsIPermissionManager.DENY_ACTION;
  963.     }
  964.     else
  965.       checkbox.hidden = true;
  966.   }
  967. }
  968.  
  969. var imagePermissionObserver = {
  970.   observe: function (aSubject, aTopic, aData)
  971.   {
  972.     if (document.getElementById("mediaPreviewBox").collapsed)
  973.       return;
  974.  
  975.     if (aTopic == "perm-changed") {
  976.       var permission = aSubject.QueryInterface(Components.interfaces.nsIPermission);
  977.       if (permission.type == "image") {
  978.         var imageTree = document.getElementById("imagetree");
  979.         var row = imageTree.currentIndex;
  980.         var item = gImageView.data[row][COL_IMAGE_NODE];
  981.         var url = gImageView.data[row][COL_IMAGE_ADDRESS];
  982.         if (makeURI(url).host == permission.host)
  983.           makeBlockImage(url);
  984.       }
  985.     }
  986.   }
  987. }
  988.  
  989. function getContentTypeFromHeaders(cacheEntryDescriptor)
  990. {
  991.   if (!cacheEntryDescriptor)
  992.     return null;
  993.  
  994.   return (/^Content-Type:\s*(.*?)\s*(?:\;|$)/mi
  995.           .exec(cacheEntryDescriptor.getMetaDataElement("response-head")))[1];
  996. }
  997.  
  998. //******** Other Misc Stuff
  999. // Modified from the Links Panel v2.3, http://segment7.net/mozilla/links/links.html
  1000. // parse a node to extract the contents of the node
  1001. function getValueText(node)
  1002. {
  1003.   var valueText = "";
  1004.  
  1005.   // form input elements don't generally contain information that is useful to our callers, so return nothing
  1006.   if (node instanceof HTMLInputElement ||
  1007.       node instanceof HTMLSelectElement ||
  1008.       node instanceof HTMLTextAreaElement)
  1009.     return valueText;
  1010.  
  1011.   // otherwise recurse for each child
  1012.   var length = node.childNodes.length;
  1013.   for (var i = 0; i < length; i++) {
  1014.     var childNode = node.childNodes[i];
  1015.     var nodeType = childNode.nodeType;
  1016.  
  1017.     // text nodes are where the goods are
  1018.     if (nodeType == Node.TEXT_NODE)
  1019.       valueText += " " + childNode.nodeValue;
  1020.     // and elements can have more text inside them
  1021.     else if (nodeType == Node.ELEMENT_NODE) {
  1022.       // images are special, we want to capture the alt text as if the image weren't there
  1023.       if (childNode instanceof HTMLImageElement)
  1024.         valueText += " " + getAltText(childNode);
  1025.       else
  1026.         valueText += " " + getValueText(childNode);
  1027.     }
  1028.   }
  1029.  
  1030.   return stripWS(valueText);
  1031. }
  1032.  
  1033. // Copied from the Links Panel v2.3, http://segment7.net/mozilla/links/links.html
  1034. // traverse the tree in search of an img or area element and grab its alt tag
  1035. function getAltText(node)
  1036. {
  1037.   var altText = "";
  1038.  
  1039.   if (node.alt)
  1040.     return node.alt;
  1041.   var length = node.childNodes.length;
  1042.   for (var i = 0; i < length; i++)
  1043.     if ((altText = getAltText(node.childNodes[i]) != undefined))  // stupid js warning...
  1044.       return altText;
  1045.   return "";
  1046. }
  1047.  
  1048. // Copied from the Links Panel v2.3, http://segment7.net/mozilla/links/links.html
  1049. // strip leading and trailing whitespace, and replace multiple consecutive whitespace characters with a single space
  1050. function stripWS(text)
  1051. {
  1052.   var middleRE = /\s+/g;
  1053.   var endRE = /(^\s+)|(\s+$)/g;
  1054.  
  1055.   text = text.replace(middleRE, " ");
  1056.   return text.replace(endRE, "");
  1057. }
  1058.  
  1059. function setItemValue(id, value)
  1060. {
  1061.   var item = document.getElementById(id);
  1062.   if (value) {
  1063.     item.parentNode.collapsed = false;
  1064.     item.value = value;
  1065.   }
  1066.   else
  1067.     item.parentNode.collapsed = true;
  1068. }
  1069.  
  1070. function formatNumber(number)
  1071. {
  1072.   return (+number).toLocaleString();  // coerce number to a numeric value before calling toLocaleString()
  1073. }
  1074.  
  1075. function formatDate(datestr, unknown)
  1076. {
  1077.   // scriptable date formatter, for pretty printing dates
  1078.   var dateService = Components.classes["@mozilla.org/intl/scriptabledateformat;1"]
  1079.                               .getService(Components.interfaces.nsIScriptableDateFormat);
  1080.  
  1081.   var date = new Date(datestr);
  1082.   if (!date.valueOf())
  1083.     return unknown;
  1084.  
  1085.   return dateService.FormatDateTime("", dateService.dateFormatLong,
  1086.                                     dateService.timeFormatSeconds,
  1087.                                     date.getFullYear(), date.getMonth()+1, date.getDate(),
  1088.                                     date.getHours(), date.getMinutes(), date.getSeconds());
  1089. }
  1090.  
  1091. function doCopy()
  1092. {
  1093.   if (!gClipboardHelper)
  1094.     return;
  1095.  
  1096.   var elem = document.commandDispatcher.focusedElement;
  1097.  
  1098.   if (elem && "treeBoxObject" in elem) {
  1099.     var view = elem.view;
  1100.     var selection = view.selection;
  1101.     var text = [], tmp = '';
  1102.     var min = {}, max = {};
  1103.  
  1104.     var count = selection.getRangeCount();
  1105.  
  1106.     for (var i = 0; i < count; i++) {
  1107.       selection.getRangeAt(i, min, max);
  1108.  
  1109.       for (var row = min.value; row <= max.value; row++) {
  1110.         view.performActionOnRow("copy", row);
  1111.  
  1112.         tmp = elem.getAttribute("copybuffer");
  1113.         if (tmp)
  1114.           text.push(tmp);
  1115.         elem.removeAttribute("copybuffer");
  1116.       }
  1117.     }
  1118.     gClipboardHelper.copyString(text.join("\n"));
  1119.   }
  1120. }
  1121.  
  1122. function doSelectAll()
  1123. {
  1124.   var elem = document.commandDispatcher.focusedElement;
  1125.  
  1126.   if (elem && "treeBoxObject" in elem)
  1127.     elem.view.selection.selectAll();
  1128. }
  1129.